/*
 * Copyright (c) 2010, Davide Brugali, All right reserved
 * 
 * Project VisualizerJava3D
 * 
 * Package motionplanning.cartspace.tools
 */
package star.planets.meshview;



import java.awt.GraphicsConfiguration;

import java.util.ArrayList;
import java.util.Enumeration;

import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.LineArray;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.swing.JPanel;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;

import star.crust.cartspace.framework.CartesianSpace;
import star.crust.cartspace.framework.CrtBody;
import star.crust.cartspace.framework.CrtBodyGroup;
import star.crust.cartspace.framework.CrtLoaderCollada;

import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseWheelZoom;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class J3DSceneCanvas  extends JPanel {
	private static final long serialVersionUID = 1L;
	private SimpleUniverse univ = null;
    private BranchGroup scene = null;
    private TransformGroup sceneTrans = null;
    private Canvas3D canvas = null;
	private CartesianSpace crtSpace = null;
	private ArrayList<J3DBody> bodyList = new ArrayList<J3DBody>();

	public J3DSceneCanvas() {
    	// create the Cartesian Space
    	crtSpace = new CartesianSpace();
//		robotPose = crtSpace.newPose();
    	
		this.setLayout(new java.awt.BorderLayout());
		this.setPreferredSize(new java.awt.Dimension(1200, 700));

		// Get the preferred graphics configuration for the default screen
		GraphicsConfiguration config =
			SimpleUniverse.getPreferredConfiguration();
		// Create a Canvas3D using the preferred configuration
		canvas = new Canvas3D(config);
		// Create simple universe with view branch
		
		univ = new SimpleUniverse(canvas);
		// This will move the ViewPlatform back a bit so the
		// objects in the scene can be viewed.
		univ.getViewingPlatform().setNominalViewingTransform();
		// Ensure at least 5 msec per frame (i.e., < 200Hz)
		univ.getViewer().getView().setMinimumFrameCycleTime(5);
		this.add(canvas, java.awt.BorderLayout.CENTER);    	
		
		scene = new BranchGroup();
		
		// Create the TransformGroup node and initialize it to the
		// identity. Enable the TRANSFORM_WRITE capability so that
		// our behavior code can modify it at run time. 
		sceneTrans = new TransformGroup();
		sceneTrans.setCapability(TransformGroup.ALLOW_CHILDREN_WRITE);
		sceneTrans.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
		sceneTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		sceneTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		
		Transform3D t3d = new Transform3D();
		t3d.setScale(0.001);
		sceneTrans.setTransform(t3d);
		scene.addChild(sceneTrans);

		/* Create Floor*/
        TransformGroup floorTrans = new TransformGroup();
        floorTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		Transform3D floorT3d = new Transform3D();
		floorT3d.rotX(1);
		floorTrans.setTransform(t3d);
		floorTrans.addChild(this.createFloor(50));

		sceneTrans.addChild(floorTrans);

		
		// Create the mouse behaviours
		BoundingSphere bounds =
			new BoundingSphere(new Point3d(0.0,0.0,0.0), 10000.0);

        MouseRotate mr = new MouseRotate(canvas, sceneTrans);
        mr.setSchedulingBounds(bounds);
        mr.setSchedulingInterval(1);
        sceneTrans.addChild(mr);

        MouseTranslate mt = new MouseTranslate(canvas, sceneTrans);
        mt.setSchedulingBounds(bounds);
        mt.setSchedulingInterval(1);
        sceneTrans.addChild(mt);
        
        MouseZoom mz = new MouseZoom(sceneTrans);
        mz.setSchedulingBounds(bounds);
        mz.setSchedulingInterval(1);
        sceneTrans.addChild(mz);
        
        MouseWheelZoom mwz = new MouseWheelZoom(sceneTrans);
        mwz.setSchedulingBounds(bounds);
        mwz.setSchedulingInterval(1);
        sceneTrans.addChild(mwz);

		// Have Java 3D perform optimizations on this scene graph.
		scene.compile();
		univ.addBranchGraph(scene);		
    }

	private Shape3D createFloor(int nDivision) {
		float width = 10000000.0f;		
		float offset = width/nDivision;
		int n = (int) (nDivision + 1)*4;
		float l = -width/2;

		// Line Array
		LineArray landGeom = new LineArray(n, GeometryArray.COORDINATES|GeometryArray.COLOR_3);
		for(int c=0; c<n; c+=4)
		{
			landGeom.setCoordinate(c+0, new Point3f(-width/2,0.0f,l));
			landGeom.setCoordinate(c+1, new Point3f(width/2,0.0f,l));
			landGeom.setCoordinate(c+2, new Point3f(l,0.0f,-width/2));
			landGeom.setCoordinate(c+3, new Point3f(l,0.0f,width/2));
			l += offset; 
		}

		// Create color 
		Color3f c = new Color3f(0.7f,0.7f,0.7f);
		for(int i=0; i<n; i++) landGeom.setColor(i,c);

		return new Shape3D(landGeom);
	}
	CrtBodyGroup loadModel(String fileName) {
        TransformGroup crtSpaceTrans = new TransformGroup();
        crtSpaceTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		Transform3D crtSpaceT3d = new Transform3D();
		crtSpaceT3d.rotX(-Math.PI/2);
		crtSpaceTrans.setTransform(crtSpaceT3d);
		crtSpaceTrans.addChild(this.createFloor(100));

    	// create the COLLADA loader
    	CrtLoaderCollada sceneLoader = new CrtLoaderCollada(fileName);
    	CrtBodyGroup rootBodyGroup = crtSpace.loadMeshModel(sceneLoader);
				
		if( rootBodyGroup == null) {
			System.out.println("\n\nDocument " + fileName + " not loaded");
			return null;
		}
		System.out.println("\n\nDocument " + fileName + " loaded");

		// create a J3DBody for each rigid body in the crtSpace,
		// add it to the body list and 
		// attach it to the scene transform group "sceneTrans"
		
		J3DBody j3dBody = null;
		Enumeration<CrtBody> bodyIterator = crtSpace.bodyIterator();
		CrtBody crtBody = null;
		while(bodyIterator.hasMoreElements()) {
			crtBody = bodyIterator.nextElement();
			j3dBody = new J3DBody(crtBody);
			bodyList.add(j3dBody);
			if(j3dBody.getRoot() != null)
				crtSpaceTrans.addChild(j3dBody.getRoot());
		}
		
		
		BranchGroup crtSpaceGroup = new BranchGroup();
		crtSpaceGroup.addChild(crtSpaceTrans);
		sceneTrans.addChild(crtSpaceGroup);
		
		return rootBodyGroup;
	}
}
